/**
 * LinkedLST
 * May 12, 2011
 * ScannerManager.java - Manages the camera and callbacks for barcode scanning
 *
 * Based off example source code at:
 * http://www.arp123.com/post/Identified-in-the-Android-use-ZXing-barcode-QR-Code.html
 */

package edu.washington.cs.labspecimentransport.ops; 
import java.io.IOException; 
import java.util.Timer;
import java.util.TimerTask;

import android.graphics.PixelFormat; 
import android.hardware.Camera;  
import android.view.SurfaceHolder; 

/**
 * ScannerManager is a module for managing a camera and visual overlays used for
 * barcode scanning as well performing the appropriate callbacks for each scan attempt.
 */
public class ScannerManager implements SurfaceHolder.Callback { 
    
	private SurfaceHolder holder; 
    private Camera camera;  
    private Camera.PreviewCallback previewCallback;
    private AutofocusTask scanTask;
    private Timer scanTimer; 
    
    // preferred dimensions for the camera preview
    private int width, height;
    
    // lock for start and stopping timers
    private boolean timerIsRunning;
    private boolean previewStarted;
    
    // time (in milliseconds) between each autofocus attempt
    public static final int SCAN_INTERVAL = 1000;
       
    /**
     * Initializes the ScannerManager.
     * 
     * @param context the Activity containing the camera SurfaceView
     * @param holder the SurfaceHolder for the camera preview's SurfaceView
     * @param scanArea view holding the scan area
     * @param width preferred width of camera preview
     * @param height preferred height of camera preview
     * @param previewCallback the callback to perform for each scan iteration
     */
    public ScannerManager (SurfaceHolder holder, int width, int height, 
    		Camera.PreviewCallback previewCallback) { 
    	
    	this.holder = holder; 
        this.holder.addCallback(this); 
        this.holder.setType (SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

        this.width = width; 
        this.height = height; 
        this.previewCallback = previewCallback; 
              
        // initialize timer task
        scanTask = new AutofocusTask();
        
        timerIsRunning = false;
        previewStarted = false;
    }
    
    /**
     * Start all scanning tasks.
     */
    public void startScanning() {
    	if (!timerIsRunning) {
    		System.out.println("Starting scanner...");
    		scanTimer = new Timer();
    		scanTask = new AutofocusTask();
    		scanTimer.schedule (scanTask, 0, SCAN_INTERVAL); 
    		timerIsRunning = true;
    		if (camera != null) {
    			camera.setPreviewCallback(previewCallback);
    		}
    	}
    }
    
    /**
     * Stop all scanning tasks.
     */
    public void stopScanning() {
    	if (timerIsRunning) {
    		System.out.println("Stopping scanner...");
    		scanTimer.cancel();
    		timerIsRunning = false;
    		if (camera != null) {
    			camera.setPreviewCallback(null);
    		}
    	}
    }

    public void surfaceChanged (SurfaceHolder sHolder, int format, int aHeight, int aWidth) { 
        // start the preview, if it isn't already running
        camera.startPreview ();
        previewStarted = true;
    } 

    public void surfaceCreated (SurfaceHolder sHolder) { 
    	System.out.print("Opening the camera...");
    	
    	// start the camera service 
        camera = Camera.open ();
        try { 
        	// set where the preview will be displayed and its properties
            camera.setPreviewDisplay (holder);
            
        	Camera.Parameters parameters = camera.getParameters (); 
            parameters.setPreviewSize (width, height); // set the size 
            parameters.setPictureFormat (PixelFormat.JPEG); 
            camera.setParameters (parameters);
            camera.setPreviewCallback(previewCallback);
        } catch (IOException e) {
        	this.stopScanning();
            camera.release (); 
            camera = null; 
        } 
           
    } 

    public void surfaceDestroyed (SurfaceHolder sHolder) { 
    	this.stopScanning();
		
    	camera.setPreviewCallback (null); 
        camera.stopPreview ();
        previewStarted = false;
        camera.release();
        camera = null;
    } 
    
    /**
     * Timer for scheduling the camera autofocus
     */
    class AutofocusTask extends TimerTask { 
        @ Override 
        public void run() { 
            // attempt to autofocus the camera
            if (camera != null && timerIsRunning && previewStarted) 
                camera.autoFocus(null);
        } 
    }
} 